/* 
 * File:   JVersionRepository.h
 * Author: johnneyshi
 *
 * Created on 2013年4月23日, 下午1:34
 */

#ifndef JVERSIONREPOSITORY_H
#define	JVERSIONREPOSITORY_H

#include <list>
#include "JRepositoryConfig.h"
#include "JRepositoryOperationResult.h"
#include <iostream>
#include "JBaseFile.h"
#include "JDir.h"
#include "JFile.h"
#include "JSerialize.h"
#include "JVersionRepository.h"

/*
 * 这个类是versionRepository中的Node中每个条目的信息
 */

class VersionRepositoryNodeDataItem : public JSerialize
{
public:
    //Serialize begin.
    string relativeFullFileName;
    string fileOrDir;
    string convertedFileName;//这个是当是文件时，代表其在当前文件下的文件名，这个由JUuid产生
    //Serialize end.
    VersionRepositoryNodeDataItem(string _relative,string _fileOrDir):relativeFullFileName(_relative),fileOrDir(_fileOrDir)
    {
        
    }
    VersionRepositoryNodeDataItem()
    {
        
    }
    int Serialize(JInOutPut& strea,int& allSize)
    {
       int classSize = 0,selfSize = 0;
       JSerialize::SerializeHead(strea,selfSize,classSize);
       
       JSerialize::Serialize(strea,relativeFullFileName,classSize);
       JSerialize::Serialize(strea,fileOrDir,classSize);
       JSerialize::Serialize(strea,convertedFileName,classSize);
       
       return JSerialize::SerializeTail(strea,allSize,selfSize,classSize);
    }
    int ReSerialize(JInOutPut& strea)
    {
        int classSize = JSerialize::ReSerializeHead(strea);
        relativeFullFileName = JSerialize::ReSerializeString(strea);
        fileOrDir = JSerialize::ReSerializeString(strea);
        convertedFileName = JSerialize::ReSerializeString(strea);
        return classSize;
    }
    //这里判断相等，应该去掉前面两个
    bool operator == (const VersionRepositoryNodeDataItem& item)
    {
        if(JBaseFile::IsEqual(this->relativeFullFileName,item.relativeFullFileName,2))
        {
            return true;
        }
        return false;
    }
};  
/*
 * 这个类是versionRepository中每个Node的信息
 */



class VersionRepositoryNodeData : public JSerialize
{
public:
    //Serialize begin.
    string convertedFileName;//这个是当是文件时，代表其在当前文件下的文件名，这个由JUuid产生
    string fileOrDir;
    JBaseFile baseFile;
    std::list<VersionRepositoryNodeDataItem> listItem;
    //Serialize end.
    friend std::ostream& operator << (std::ostream& os,const VersionRepositoryNodeData& data);
    VersionRepositoryNodeData()
    {
        
    }
    /*传入比如现在位于节点/repos/2/dir，那么在本data的listItem中查找/dir/dir2这个节点，然后返回pair<版本号，相应的relativeFileName>
     * 如果没有，那么versionID = -1;
     */
    std::pair<int,string> GetListItem(string _relativeFileName);

    
    VersionRepositoryNodeData(JBaseFile& _basefile,std::string _fileOrDir)
    {
        fileOrDir = _fileOrDir;
        baseFile = _basefile;
    }
    int Serialize(JInOutPut& strea,int& allSize)
    {
        int classSize = 0,selfSize = 0;
        JSerialize::SerializeHead(strea,selfSize,classSize);
        JSerialize::Serialize(strea,convertedFileName,classSize);
        JSerialize::Serialize(strea,fileOrDir,classSize);
        baseFile.Serialize(strea,classSize);
        JSerialize::Serialize<VersionRepositoryNodeDataItem>(strea,listItem,classSize);
        
        return JSerialize::SerializeTail(strea,allSize,selfSize,classSize);
    }
    int ReSerialize(JInOutPut& strea)
    {
        int classSize = JSerialize::ReSerializeHead(strea);
        convertedFileName = JSerialize::ReSerializeString(strea);
        fileOrDir = JSerialize::ReSerializeString(strea);
        baseFile.ReSerialize(strea);
        listItem = JSerialize::ReSerializeList<VersionRepositoryNodeDataItem>(strea);
        return classSize;
    }
};



class MultipleTreeNodeCompareFilePath : public IMultipleTreeNodeCompare<string>
{
public:
    bool IsAncestor(const string& _node1,const string& _node2)
    {
        return JBaseFile::IsAncestor(_node1,_node2);
    }
    //这里需要注意系统的不一样，目录的组织格式也不一样
    virtual std::list<string> GenerateAncestor(const string& _data)
    {
        return JBaseFile::GenerateAncestor(_data);
    }
    int Compare(const string& _node1,const string& _node2)
    {
        return JBaseFile::Compare(_node1,_node2);
    }
private:

};

class JVersionRepository : JSerialize
{
public:
    static void AddNodeSuccessEvent(MultipleTreeNode<std::string,VersionRepositoryNodeData>* pNode);
    JVersionRepository();
    virtual ~JVersionRepository();
    //Serialize begin.
    int versionID;
    MultipleTree<std::string,VersionRepositoryNodeData>* pTree;
    //Serialize end.
    
    
    JRepositoryConfig config;
    
    
    JRepositoryOperationResult Add(JFile& _file);
    JRepositoryOperationResult Add(JDir& _dir);
    
    JRepositoryOperationResult Delete(JFile& _file);
    JRepositoryOperationResult Delete(JDir& _dir);
    
    /*如果fileName是文件，那么SearchResult里面的fileOrDir="file",并且listFile的第一个是这个文件的内容
     * 如果fileName是目录，那么SearchResult里面的fileOrDir="dir",listFile和listDir是这个目录下的信息
     * 如果_fileName为""，那么返回根目录也就是目录/repos/0的目录
     */
    JRepositorySearchResult Search(string _fileName = "");
    
    JRepositoryOperationResult Modify(JFile& _file1,JFile& _file2);
    JRepositoryOperationResult Modify(JDir& _dir1,JDir& _dir2);
    
    JRepositoryOperationResult CreateAVersion(int _versionID);
    JRepositoryOperationResult ReadTheVersion(int _versionID);
    
    int Serialize(JInOutPut& strea,int& allSize);
    int ReSerialize(JInOutPut& strea);
    
    /*这个函数是和Serialize的不同点是，这个函数已经提供了stream*/
    int InitiativeSerialize();
    /*这个函数是和Serialize的不同点是，这个函数已经提供了stream*/
    int InitiativeReSerialize(int _versionID);
        /*把目录如/repos/1/dir/dir1分割成pair(1,"/dir/dir1")*/
    static std::pair<int,std::string> SplitRelativePath(std::string _relativePath);
private:
//    //这个版本的根目录，比如/home/johnneyshi/repos/1表示版本1的根目录
//    std::string versionDir;
    JVersionRepository* pPreviousVersion;
    //保存了所有的被读出的版本信息
    std::list<JVersionRepository*> listPVersion;
    /*从listPOtherVersion中检索出版本，如果存在，那么直接搜索出，如果没有，那么读取后再存入listPOtherVersion，再返回*/
    JVersionRepository* GetListPVersion(int _versionID);
    //复制上一个版本中，_relativePath的父节点的信息到本版本中
    JRepositoryOperationResult CopyFromPreviousVersion(std::string _relativePath);
    
    JRepositoryOperationResult Add(JBaseFile& _baseFile,string fileOrDir = "dir");
    JRepositoryOperationResult Delete(JBaseFile& _baseFile,string fileOrDir = "dir");
    //这里的_node还是上一个版本的，构造节点由这个函数完成
    JRepositoryOperationResult AddToTree(MultipleTreeNode<string,VersionRepositoryNodeData>& _node,JBaseFile& _baseFile);
    
    //判断在这棵树中，是否已经有了这个目录
    bool IsExist(string _relativeFilePath);
    
    //把/dir1/dir12转换成/repos/1/dir1/dir12的形式
    static std::string GenerateRelativePath(int _versionID,std::string s);
    //修改版本目录，比如/repos/1/dir1/dir12转换为/repos/2/dir1/dir12
    static std::string ModifyVersionPath(int _versionID,std::string s);
    /*
     * 比如现在是在版本2，而父目录中有一个item="/repos/1/dir1",而此时当前节点为"/repos/2/dir2"
     * 那么就需要把这个item改为"/repos/2/dir2",而如果父目录中没有这个item，那么就不是更新，而是加入了
     */
    void AddOrUpdateData(MultipleTreeNode<string,VersionRepositoryNodeData>* pParent,VersionRepositoryNodeDataItem& _item);
    JVersionRepository* OpenPreviousVersion(int _versionID);
    JVersionRepository* OpenAVersion(int _versionID);
    /*根据relativeName去相应的版本，查找文件信息,_baseFile应该传入JFile或者JDir*/
    void GetBaseFileInfoByData(VersionRepositoryNodeData& data,JBaseFile& _baseFile);
    /*根据data,产生SearchResult*/
    void AddToSearchResult(JRepositorySearchResult& _result,VersionRepositoryNodeData& _data);
};

#endif	/* JVERSIONREPOSITORY_H */

